
using System;
using System.Runtime.InteropServices;

namespace CUtil.Win32
{
	public interface IKeyboardHook
	{
	}

	/// <summary>
	/// This delegate is used for implementing the callback method for the keyboard-hook.
	/// </summary>
	internal delegate bool KeyboardHook_Delegate(int nCode);

	/// <summary>
	/// </summary>
	internal class KeyboardHook
	{
	
		#region Win32 DLL imports.
		[DllImport("user32", EntryPoint="SetWindowsHookEx")]
		private static extern System.IntPtr Win32_SetKeyboardHook(int idHook, KeyboardHook_Delegate callBackProc, System.IntPtr hMod, System.UInt32 threadID);
		
		[DllImport("user32", EntryPoint="CallNextHookEx")]
		private static extern System.IntPtr Win32_CallNextHook(int idHookCode, System.IntPtr wParam, ref CUtil.Win32._MouseHookStruct hookStruct);

		[DllImport("user32", EntryPoint="UnhookWindowsHookEx")]
		private static extern bool Win32_UnhookWindowsHook(System.IntPtr hookHandle);

		[DllImport("kernel32", EntryPoint="GetCurrentThreadId")]
		private static extern System.UInt32 Win32_GetCurrentThreadID();
		#endregion

		#region Singleton pattern implementation.
		/// <summary>
		/// This static private member contains the one and only mouse hook object in the application. 
		/// </summary>
		private static KeyboardHook GlobalKeyboardHook;

		/// <summary>
		/// This static property allows us to retrieve the global mouse hook object.
		/// </summary>
		internal static KeyboardHook KeyboardHookObject
		{
			get
			{
				if(null == GlobalKeyboardHook)
				{
					GlobalKeyboardHook = new KeyboardHook();
				}
				return(GlobalKeyboardHook);
			}
		}
		#endregion

		/// <summary>
		/// This static method allows us to set a mouse hook. Note, that the the hook is only application local
		/// and not global to the system.
		/// </summary>
		/// <param name="callBackProc"></param>
		/// <returns></returns>
		private static System.IntPtr SetKeyboardHook(KeyboardHook_Delegate callBackProc)
		{
			System.UInt32 threadID = Win32_GetCurrentThreadID();
			return(Win32_SetKeyboardHook(HookTypes.WH_KEYBOARD, callBackProc, System.IntPtr.Zero, threadID));
		}

		#region Instance member data.
	

	

	

		/// <summary>
		/// This event is raised every time a mouse hook event occurs with the HC_ACTION value. The consumer of this
		/// event will receive the current position of the mouse in screen coordinates.
		/// </summary>
		//		private event MouseNotifyEventHandler MouseNotification;
		#endregion

/*
		public event KeyboardHook_Delegate KeyboardHook 
		{  
			// The add event accessor method.
			add { AddEventHandler(value); }
			// The remove event accessor method.
			remove { RemoveEventHandler(value); }
		}
*/
	}
}

		/*
				/// <summary>
				/// This method raises the event for a mouse notification.
				/// </summary>
				/// <param name="ptMouse">The point of the mouse event. This point contains screen coordinates.</param>
				protected virtual void OnMouseNotification(System.Drawing.Point ptMouse)
				{
					if(null != this.MouseNotification)
					{
						this.MouseNotification(ptMouse);
					}
				}

				/// <summary>
				/// The concept we use here is a little bit different from the event-delegate mechanism used in the .NET
				/// framework. We use a private event and allow a consumer to attach and detach itself by calling the 
				/// appropriate method. This is required, because we don't want to hook the mouse all the time. The mouse
				/// hook will only be installed if at least one consumer attaches to the event.
				/// </summary>
				/// <param name="notifyHandler">The notification handler to be attached for mouse hook event notifications.</param>
				public void Attach(MouseNotifyEventHandler notifyHandler)
				{
					this.MouseNotification += notifyHandler;

					if((null != this.MouseNotification) && (System.IntPtr.Zero == this.hookHandle))
					{
						MouseHook_Delegate hookCallBack = new MouseHook_Delegate(this.MouseHookProc);
						this.gcMouseHookObjectHandle = System.Runtime.InteropServices.GCHandle.Alloc(hookCallBack);
						this.hookHandle = SetMouseHook(hookCallBack);
					}
				}

				/// <summary>
				/// The corresponding detach method to the attach method. For more details see the attach method description.
				/// </summary>
				/// <param name="notifyHandler">The notification handler to be detached.</param>
				public void Detach(MouseNotifyEventHandler notifyHandler)
				{
					this.MouseNotification -= notifyHandler;

					if((null == this.MouseNotification) && (System.IntPtr.Zero != this.hookHandle))
					{
						Win32_UnhookWindowsHook(this.hookHandle);
						this.hookHandle = System.IntPtr.Zero;
						this.gcMouseHookObjectHandle.Free();
					}
				}

				/// <summary>
				/// This is the method that will hook into the mouse events of the application.
				/// Note: The thread that calls into this method might not neccessarily be the GUI thread of the application.
				/// </summary>
				/// <param name="nCode">The code that specifies the event that has occured.</param>
				/// <param name="wParam"></param>
				/// <param name="hookStruct"></param>
				/// <returns></returns>
				private System.IntPtr KeyboardHookProc(int nCode, System.IntPtr wParam, ref CUtil._MouseHookStruct hookStruct)
				{
					switch(nCode)
					{
						case HookCodes.HC_ACTION:
						{
							OnMouseNotification(new System.Drawing.Point(hookStruct.ptMouse.xPos, hookStruct.ptMouse.yPos));
							break;
						}
					}

					return(Win32_CallNextHook(nCode, wParam, ref hookStruct));
				}
		*/		
